//package cn.oyzh.jeditermfx.terminal;
//
//import cn.oyzh.jeditermfx.core.input.InputEvent;
//import cn.oyzh.jeditermfx.core.util.Ascii;
//import cn.oyzh.jeditermfx.terminal.util.CharUtils;
//import cn.oyzh.jeditermfx.core.Platform;
//import org.jetbrains.annotations.NotNull;
//
//import java.util.HashMap;
//import java.util.Map;
//import java.util.Objects;
//
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_BACK_SPACE;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_DELETE;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_DOWN;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_END;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_ENTER;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_F1;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_F10;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_F11;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_F12;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_F2;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_F3;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_F4;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_F5;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_F6;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_F7;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_F8;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_F9;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_HOME;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_INSERT;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_KP_DOWN;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_KP_LEFT;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_KP_RIGHT;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_KP_UP;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_LEFT;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_PAGE_DOWN;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_PAGE_UP;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_RIGHT;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_TAB;
//import static cn.oyzh.jeditermfx.core.input.KeyEvent.VK_UP;
//
///**
// * @author traff
// */
//public class TerminalKeyEncoder {
//
//    private static final int ESC = Ascii.ESC;
//
//    private final Platform myPlatform;
//
//    private final Map<KeyCodeAndModifier, byte[]> myKeyCodes = new HashMap<>();
//
//    private boolean myAltSendsEscape = true;
//
//    private boolean myMetaSendsEscape = false;
//
//    public TerminalKeyEncoder() {
//        this(Platform.current());
//    }
//
//    public TerminalKeyEncoder(@NotNull Platform platform) {
//        myPlatform = platform;
//        setAutoNewLine(false);
//        arrowKeysAnsiCursorSequences();
//        configureLeftRight();
//        keypadAnsiSequences();
//        putCode(VK_BACK_SPACE, Ascii.DEL);
//        putCode(VK_F1, ESC, 'O', 'P');
//        putCode(VK_F2, ESC, 'O', 'Q');
//        putCode(VK_F3, ESC, 'O', 'R');
//        putCode(VK_F4, ESC, 'O', 'S');
//        putCode(VK_F5, ESC, '[', '1', '5', '~');
//        putCode(VK_F6, ESC, '[', '1', '7', '~');
//        putCode(VK_F7, ESC, '[', '1', '8', '~');
//        putCode(VK_F8, ESC, '[', '1', '9', '~');
//        putCode(VK_F9, ESC, '[', '2', '0', '~');
//        putCode(VK_F10, ESC, '[', '2', '1', '~');
//        putCode(VK_F11, ESC, '[', '2', '3', '~');
//        putCode(VK_F12, ESC, '[', '2', '4', '~');
//        putCode(VK_INSERT, ESC, '[', '2', '~');
//        putCode(VK_DELETE, ESC, '[', '3', '~');
//        putCode(VK_PAGE_UP, ESC, '[', '5', '~');
//        putCode(VK_PAGE_DOWN, ESC, '[', '6', '~');
//        putCode(VK_HOME, ESC, '[', 'H');
//        putCode(VK_END, ESC, '[', 'F');
//        putCode(new KeyCodeAndModifier(VK_TAB, InputEvent.SHIFT_MASK), ESC, '[', 'Z');
//    }
//
//    public void arrowKeysApplicationSequences() {
//        putCode(VK_UP, ESC, 'O', 'A');
//        putCode(VK_DOWN, ESC, 'O', 'B');
//        putCode(VK_RIGHT, ESC, 'O', 'C');
//        putCode(VK_LEFT, ESC, 'O', 'D');
//    }
//
//    public void arrowKeysAnsiCursorSequences() {
//        putCode(VK_UP, ESC, '[', 'A');
//        putCode(VK_DOWN, ESC, '[', 'B');
//        putCode(VK_RIGHT, ESC, '[', 'C');
//        putCode(VK_LEFT, ESC, '[', 'D');
//    }
//
//    private void configureLeftRight() {
//        if (myPlatform == Platform.macOS) {
//            putCode(new KeyCodeAndModifier(VK_RIGHT, InputEvent.ALT_MASK), ESC, 'f'); // ^[f
//            putCode(new KeyCodeAndModifier(VK_LEFT, InputEvent.ALT_MASK), ESC, 'b'); // ^[b
//        } else {
//            putCode(new KeyCodeAndModifier(VK_LEFT, InputEvent.CTRL_MASK), ESC, '[', '1', ';', '5', 'D'); // ^[[1;5D
//            putCode(new KeyCodeAndModifier(VK_RIGHT, InputEvent.CTRL_MASK), ESC, '[', '1', ';', '5', 'C'); // ^[[1;5C
//            putCode(new KeyCodeAndModifier(VK_LEFT, InputEvent.ALT_MASK), ESC, '[', '1', ';', '3', 'D'); // ^[[1;3D
//            putCode(new KeyCodeAndModifier(VK_RIGHT, InputEvent.ALT_MASK), ESC, '[', '1', ';', '3', 'C'); // ^[[1;3C
//        }
//    }
//
//    public void keypadApplicationSequences() {
//        putCode(VK_KP_DOWN, ESC, 'O', 'B'); //2
//        putCode(VK_KP_LEFT, ESC, 'O', 'D'); //4
//        putCode(VK_KP_RIGHT, ESC, 'O', 'C'); //6
//        putCode(VK_KP_UP, ESC, 'O', 'A'); //8
//        putCode(VK_HOME, ESC, 'O', 'H');
//        putCode(VK_END, ESC, 'O', 'F');
//    }
//
//    public void keypadAnsiSequences() {
//        putCode(VK_KP_DOWN, ESC, '[', 'B'); //2
//        putCode(VK_KP_LEFT, ESC, '[', 'D'); //4
//        putCode(VK_KP_RIGHT, ESC, '[', 'C'); //6
//        putCode(VK_KP_UP, ESC, '[', 'A'); //8
//        putCode(VK_HOME, ESC, '[', 'H');
//        putCode(VK_END, ESC, '[', 'F');
//    }
//
//    void putCode(final int code, final int... bytesAsInt) {
//        myKeyCodes.put(new KeyCodeAndModifier(code, 0), CharUtils.makeCode(bytesAsInt));
//    }
//
//    private void putCode(@NotNull KeyCodeAndModifier key, final int... bytesAsInt) {
//        myKeyCodes.put(key, CharUtils.makeCode(bytesAsInt));
//    }
//
//    public byte[] getCode(final int key, int modifiers) {
//        byte[] bytes = myKeyCodes.get(new KeyCodeAndModifier(key, modifiers));
//        if (bytes != null) {
//            return bytes;
//        }
//        bytes = myKeyCodes.get(new KeyCodeAndModifier(key, 0));
//        if (bytes == null) {
//            return null;
//        }
//        if ((myAltSendsEscape || alwaysSendEsc(key)) && (modifiers & InputEvent.ALT_MASK) != 0) {
//            return insertCodeAt(bytes, CharUtils.makeCode(ESC), 0);
//        }
//        if ((myMetaSendsEscape || alwaysSendEsc(key)) && (modifiers & InputEvent.META_MASK) != 0) {
//            return insertCodeAt(bytes, CharUtils.makeCode(ESC), 0);
//        }
//        if (isCursorKey(key) || isFunctionKey(key)) {
//            return getCodeWithModifiers(bytes, modifiers);
//        }
//        return bytes;
//    }
//
//    private boolean alwaysSendEsc(int key) {
//        return isCursorKey(key) || key == '\b';
//    }
//
//    private boolean isCursorKey(int key) {
//        return key == VK_DOWN || key == VK_UP || key == VK_LEFT || key == VK_RIGHT || key == VK_HOME || key == VK_END;
//    }
//
//    private boolean isFunctionKey(int key) {
//        return key >= VK_F1 && key <= VK_F12 || key == VK_INSERT || key == VK_DELETE || key == VK_PAGE_UP || key == VK_PAGE_DOWN;
//    }
//
//    /**
//     * Refer to section PC-Style Function Keys in http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
//     */
//    private byte[] getCodeWithModifiers(byte[] bytes, int modifiers) {
//        int code = modifiersToCode(modifiers);
//        if (code > 0 && bytes.length > 2) {
//            // SS3 needs to become CSI.
//            if (bytes[0] == ESC && bytes[1] == 'O') bytes[1] = '[';
//            // If the control sequence has no parameters, it needs a default parameter.
//            // Either way it also needs a semicolon separator.
//            String prefix = bytes.length == 3 ? "1;" : ";";
//            return insertCodeAt(bytes, (prefix + code).getBytes(), bytes.length - 1);
//        }
//        return bytes;
//    }
//
//    private static byte[] insertCodeAt(byte[] bytes, byte[] code, int at) {
//        byte[] res = new byte[bytes.length + code.length];
//        System.arraycopy(bytes, 0, res, 0, bytes.length);
//        System.arraycopy(bytes, at, res, at + code.length, bytes.length - at);
//        System.arraycopy(code, 0, res, at, code.length);
//        return res;
//    }
//
//    /**
//     * Code     Modifiers
//     * ------+--------------------------
//     * 2     | Shift
//     * 3     | Alt
//     * 4     | Shift + Alt
//     * 5     | Control
//     * 6     | Shift + Control
//     * 7     | Alt + Control
//     * 8     | Shift + Alt + Control
//     * 9     | Meta
//     * 10    | Meta + Shift
//     * 11    | Meta + Alt
//     * 12    | Meta + Alt + Shift
//     * 13    | Meta + Ctrl
//     * 14    | Meta + Ctrl + Shift
//     * 15    | Meta + Ctrl + Alt
//     * 16    | Meta + Ctrl + Alt + Shift
//     * ------+--------------------------
//     *
//     * @param modifiers
//     * @return
//     */
//    private static int modifiersToCode(int modifiers) {
//        int code = 0;
//        if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
//            code |= 1;
//        }
//        if ((modifiers & InputEvent.ALT_MASK) != 0) {
//            code |= 2;
//        }
//        if ((modifiers & InputEvent.CTRL_MASK) != 0) {
//            code |= 4;
//        }
//        if ((modifiers & InputEvent.META_MASK) != 0) {
//            code |= 8;
//        }
//        return code != 0 ? code + 1 : code;
//    }
//
//    public void setAutoNewLine(boolean enabled) {
//        if (enabled) {
//            putCode(VK_ENTER, Ascii.CR, Ascii.LF);
//        } else {
//            putCode(VK_ENTER, Ascii.CR);
//        }
//    }
//
//    public void setAltSendsEscape(boolean altSendsEscape) {
//        myAltSendsEscape = altSendsEscape;
//    }
//
//    public void setMetaSendsEscape(boolean metaSendsEscape) {
//        myMetaSendsEscape = metaSendsEscape;
//    }
//
//    private static class KeyCodeAndModifier {
//
//        private final int myCode;
//
//        private final int myModifier;
//
//        public KeyCodeAndModifier(int code, int modifier) {
//            myCode = code;
//            myModifier = modifier;
//        }
//
//        @Override
//        public boolean equals(Object o) {
//            if (this == o) return true;
//            if (o == null || getClass() != o.getClass()) return false;
//            KeyCodeAndModifier that = (KeyCodeAndModifier) o;
//            return myCode == that.myCode && myModifier == that.myModifier;
//        }
//
//        @Override
//        public int hashCode() {
//            return Objects.hash(myCode, myModifier);
//        }
//    }
//}
